package cn.gok.springsecuritydemo4.service;

import cn.gok.springsecuritydemo4.dao.RoleDAO;
import cn.gok.springsecuritydemo4.dao.UserDAO;
import cn.gok.springsecuritydemo4.entity.Role;
import cn.gok.springsecuritydemo4.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/**
 * @author: chen fan
 * @since: 2022/11/22 15:34
 * @description:
 */
@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    UserDAO userDAO;

    @Autowired
    RoleDAO roleDAO;

    public final static String ROLE_PREFIX = "ROLE_";


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);

        //先根据用户名查询出用户信息
        User user = userDAO.selectOne(queryWrapper);
        if ( user == null){
            throw new UsernameNotFoundException("用户不存在");
        }

        /*
            查询出用户的权限信息
                在Spring Security中认为 角色和权限是一样的， 所有角色和权限都是 认为是 GrantedAuthority对象
                   向Shiro框架中，认为权限是属于角色的

                Spring Security在验证时，直接将ArrayList<GrantedAuthority>() 中的 权限和角色都取出来进行验证
                SpringSecurity中区分角色和权限：  角色前面会有一个 "ROLE_" 前缀


             实现验证的思路：
                    （1）、先查询出用户的角色 存放进  new ArrayList<GrantedAuthority>()

                    （2）、 定义一个类实现 FilterInvocationSecurityMetadataSource接口
                            重写getAttributes方法，在该方法中编写自定义验证的规则
                                 - 1）、获取到用户请求url ，比如 /user/addUser
                                 - 2）、用这个url 和 权限表t_permission 的 permission_ulr进行比较
                                       比较成功以后，由这个地址去表中反向找出能执行这个操作的 角色有哪些
                    （3）、Spring Security
                            自动使用找到角色， 执行hasRole 看用户的 new ArrayList<GrantedAuthority>()是否有相关角色
                               如果有则可以访问该请求，否则拒绝。
         */

        List<Role> roles = roleDAO.findRolesByUserName(username);

        Collection<GrantedAuthority> authorities = new HashSet<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority( ROLE_PREFIX + role.getRoleName()));
        }

        //封装UserDetails对象返回，可以返回Spring Security 提供的默认用户对象
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                // {noop}表示不进行加密，  {bcrypt}表示采用bcrypt算法进行加密
                "{noop}"+user.getPassword(),
                true,true,true,true,
                authorities
        );
    }
}
